#pragma once

#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include "Thread.hpp"

using namespace ThreadNS;

#define MAXTHREAD 5

template<class T>
class PthreadPool
{
public:
    // 这里使用生产消费模型,永远要记得consumer没有this指针1
    static void * consumer(void * arvgs) 
    {
        PthreadPool<T> * PQ =  static_cast<PthreadPool<T>*>(arvgs);
        while(true)
        {
            pthread_mutex_lock(&PQ->_mutex);  //bug?
            T _data;
            {
            if(PQ->_queue.empty())
              {   
                //若队列为空，则释放锁，去该条件变量下等待 
                pthread_cond_wait(&PQ->_condition,&PQ->_mutex);
              }
            // 走到这里队列必定不为空
            _data = PQ->_queue.front();
            PQ->_queue.pop();
            pthread_mutex_unlock(&PQ->_mutex);
            }
            // 在锁外执行任务 

            // 因为vector的下标不好控制，无法知道是谁调用的，所以一定要传上下午数据才能知_name，而且传上下文数据扩展性更强
            std::cout  <<"收到的任务 : " <<_data.toTaskString() << " " << "执行任务 : " <<  _data() << std::endl;
            std::cout << std::endl;
            ///sleep(1);
        }

        return nullptr;
    }

public:

    
    PthreadPool(const int& _cap = MAXTHREAD)
    :_threads(_cap)
    :_capeThread(_cap)
    ,_queue(_cap) // 先把队列的大小也设置为线程的个数  , _queue不能这样初始化
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_condition,nullptr);      

        //开始创建线程但是不启动
        for(int i = 1 ; i <= _capeThread; i++)
        {
            // 线程是new出来的不要紧，最后vector会释放的
            Thread* thread = new Thread();
            _threads.push_back(thread);
        }
    }

    static PthreadPool<T>* getSingleClass()
    {   
        // 这样写可以避免_pool不为空的也来抢锁，避免不必要的竞争
        if(_pool == nullptr)
        {
            pthread_mutex_lock(&_singleLock);
            if(_pool == nullptr)
            {
                _pool = new PthreadPool<T>(); 
            }
            pthread_mutex_unlock(&_singleLock);
        }
      
        return _pool;
    }
    
    // 尽可能的删除构造的方法
    PthreadPool(const PthreadPool<T>&) = delete;
    void operator=(const PthreadPool<T>&) = delete;
    //PthreadPool<T> operator=(const PthreadPool<T>&) = delete;

    void push(const T& _data)
    {
        pthread_mutex_lock(&_mutex);
        _queue.push(_data);
        pthread_mutex_unlock(&_mutex);
        // push完成之后要，唤醒在该条件等待下的进程
        pthread_cond_signal(&_condition);
    }

    // 启动线程, 新线程负责消费
    void run()
    {
         for(auto &e : _threads)
         {                
            // 直接传一个PthreadPool类型
            e->start(consumer,(void*)this);
         }
    }

    ~PthreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_condition);
        
        // vector只能解决本身的资源，所以这里是要调析构的
        for(const auto& e : _threads)
            delete e;
    }

private:   
   std::vector<Thread*> _threads;  // 线程池, 阻塞队列
   std::queue<T> _queue;
   size_t _capeThread;

   // 这是普通的队列，用条件变量和互斥一把锁保证只有一个线程与队列交互
   pthread_cond_t  _condition;
   pthread_mutex_t _mutex;

   // 单例模式
   static PthreadPool<T>* _pool;
   static pthread_mutex_t  _singleLock;
};

template<class T>
pthread_mutex_t PthreadPool<T>::_singleLock = PTHREAD_MUTEX_INITIALIZER;

template<class T>
PthreadPool<T>* PthreadPool<T>::_pool = nullptr; 